﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TechTalk.SpecFlow;
using NUnit.Framework;
using RegCustomer;
using Infrastructure;
using Moq;

namespace SpecProj
{

    public class CreateCustomerSpecs : Setup
    {
        List<Customer> _stateMachine = new List<Customer>();

        string _newName = "NewSeanName";

        [Given(@"I have created a new Create Customer Command")]
        public void GivenIHaveCreatedANewCreateCustomerCommand()
        {
            _createNewCustomer = new CreateNewCustomerCommand(_id, _name, _version);
        }

        [When(@"I submit the Create Customer command")]
        public void WhenISubmitTheCreateCustomerCommand()
        {
            _bus.Send(_createNewCustomer);
            _version++;        
        }

        [Then(@"the customer should be created")]
        public void ThenTheCustomerShouldBeCreated()
        {
            Assert.AreEqual(_repository.GetById(_id).Id, _id);
        }

        [Then(@"a Customer Created Event should be Published")]
        public void ThenACustomerCreatedEventShouldBePublished()
        {            
            //_fakePublisher.Verify(
            //    p => p.Publish<Event>(It.IsAny<CustomerCreatedEvent>()), Times.Once());
            Assert.AreEqual(_fakeSubscriber.HandledEvents.Count, 1);
            Assert.IsInstanceOf<CustomerCreatedEvent>(
                _fakeSubscriber.HandledEvents.First().Value);
        }

        [Given(@"I have created a Customer")]
        public void GivenIHaveCreatedACustomer()
        {
            _createNewCustomer = new CreateNewCustomerCommand(_id, _name, _version);
            _bus.Send(_createNewCustomer);
            _version++;
        }

        [Given(@"I have created a new Update Customer Command")]
        public void GivenIHaveCreatedANewUpdateCustomerCommand()
        {
            _updateNewCustomer = new UpdateCustomerCommand(_id, _newName, _version);
        }

        [When(@"I submit the Update Customer Command")]
        public void WhenISubmitTheUpdateCustomerCommand()
        {
            try
            {
                _bus.Send(_updateNewCustomer);
                _version++;
            }
            catch (Exception e)
            {
                ScenarioContext.Current.Add("Exception", e);
            }
        }

        [Then(@"the customer should be updated")]
        public void ThenTheCustomerShouldBeUpdated()
        {
            Assert.AreEqual(_repository.GetById(_id).Version, _version);
        }

        [Then(@"a Customer Created Updated should be Published")]
        public void ThenACustomerCreatedUpdatedShouldBePublished()
        {
            //_fakePublisher.Verify(
            //    p => p.Publish<Event>(It.IsAny<CustomerUpdatedEvent>()), Times.Once());
            Assert.AreEqual(_fakeSubscriber.HandledEvents.Count, 2);
            Assert.IsInstanceOf<CustomerUpdatedEvent>(
                _fakeSubscriber.HandledEvents.Last().Value);
        }

        [Then(@"the command should be rejected")]
        public void ThenTheCommandShouldBeRejected()
        {
            var exception = ScenarioContext.Current["Exception"];
            Assert.That(exception, Is.Not.Null);
            Console.WriteLine("Error Produced: {0}", exception.ToString());
        }

        [Given(@"I have created a new Invalidate Customer Command")]
        public void GivenIHaveCreatedANewInvalidateCustomerCommand()
        {
            _invalidateCustomerCommand = new DeactivateCustomerCommand(_id, "my reason", _version);
        }

        [When(@"I submit the Invalidate Customer command")]
        public void WhenISubmitTheInvalidateCustomerCommand()
        {
            try
            {
                _bus.Send(_invalidateCustomerCommand);
                _version++;
            }
            catch (Exception e)
            {
                ScenarioContext.Current.Add("Exception", e);
            }
        }

        [Then(@"the customer should be marked as invalid")]
        public void ThenTheCustomerShouldBeMarkedAsInvalid()
        {
            Assert.AreEqual(_repository.GetById(_id).Version, _version);
        }

        [Then(@"a Customer Invalidated event should be Published")]
        public void ThenACustomerInvalidatedEventShouldBePublished()
        {
            //_fakePublisher.Verify(
            //    p => p.Publish<Event>(It.IsAny<CustomerInvalidatedEvent>()), Times.Once());
            Assert.AreEqual(_fakeSubscriber.HandledEvents.Count, 2);
            Assert.IsInstanceOf<CustomerDeactivatedEvent>(_fakeSubscriber.HandledEvents.Last().Value);             
        }

        [Given(@"I have marked the Customer as Invalid")]
        public void GivenIHaveMarkedTheCustomerAsInvalid()
        {
            _invalidateCustomerCommand = new DeactivateCustomerCommand(_id, "my reason", _version);
            _bus.Send(_invalidateCustomerCommand);
            _version++;
        }

        [Given(@"I have marked the Customer as Priority")]
        public void GivenIHaveMarkedTheCustomerAsPriority()
        {
            _priorityCustomerCommand = new MakeCustomerPriorityCommand(_id, _version);
            _bus.Send(_priorityCustomerCommand);
            _version++;
        }

    }

}
